package inabit.fuzzy.expressions;

import inabit.base.WorkingMemory;
import inabit.data.Variable;
import inabit.data.expression.ConsequentExpression;
import inabit.fuzzy.data.FuzzySet;
import inabit.impl.data.NumericVariable;

import java.util.ArrayList;
import java.util.List;

/**@author Rafael Rocha*/
public class FuzzyExpression extends ConsequentExpression{
	private String varId;
	private FuzzySet set;
	
	/** Can evaluate variables that aren't fuzzy variables, but can assign values
	 * to it*/
	public FuzzyExpression(String var, FuzzySet set) {
		this.varId = var;
		this.set = set;
	}
	 
	
	public Double evaluate(WorkingMemory wm) {
		
		Double result = 0.0;
		NumericVariable var = (NumericVariable)wm.getVariable(varId);
		if(var.getValue() == null) {
			if(var.getFuzzySet() != null) {
				result = set.and(var.getFuzzySet()).getMaxValue();
				return hasNot()? 1.0 - result : result;
			}
			return null;
		}
		result = set.fuzzify(Double.parseDouble(var.getValue()));
		return hasNot()? 1.0 - result : result;
	}
	public FuzzyExpression copy() {
		return new FuzzyExpression(varId, set);
	}
	public String stringForm() {
		return varId + " is " + set.getName();
	}
	@Override
	public List<Variable> getTargetVariables(WorkingMemory wm) {
		List<Variable> variables = new ArrayList<Variable>();
		variables.add(wm.getVariable(varId));
		return variables;
	}

	@Override
	public void fire(WorkingMemory wm, double truth) {
		NumericVariable var = (NumericVariable)wm.getVariable(varId);
		FuzzySet set = this.set;
		if(hasNot()) {
			set = set.negate();
		}
		if(var.getFuzzySet() == null) {
			var.setFuzzySet(set);
		}else {
			var.setFuzzySet(var.getFuzzySet().or(set));
		}
	}

	@Override
	public List<String> getReferencedVariablesIds() {
		List<String> referenced = new ArrayList<String>();
		referenced.add(varId);
		return referenced;
	}
}
